#include <cstdio>                                                                                                      
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <queue>
#include "wn.h"
#include <map>

using namespace std;
char Color[500000000];
bool RelationType[40];
#define SOURCE 1
#define DESTINATION -1
typedef struct {
    int pos;
    long offset;
} QUEUENODE;
queue<QUEUENODE> SynQueue;
static struct {
    char *option;		/* user's search request */
    int search;			/* search to pass findtheinfo() */
    int pos;			/* part-of-speech to pass findtheinfo() */
    int helpmsgidx;		/* index into help message table */
    char *label;		/* text for search header message */
} *optptr, optlist[] = {
    { "-famla", FREQ, ADJ, 5, "Familiarity" },
    { "-famln", FREQ, NOUN, 15, "Familiarity" },
    { "-famlv", FREQ, VERB, 12, "Familiarity" },
    { "-famlr", FREQ, ADV, 4, "Familiarity" },
    { NULL, 0, 0, 0, NULL }
};
static int calPath(char *, char *);
static int BFS(char *);
static int do_search(char *, int, int, int, int);
static void Init_type();
static string do_is_defined(char *);

int main()
{
    ifstream in;
    in.open("pairs");
    ofstream out;
    out.open("pairs.out.all");
    offsetflag = 1;
    Init_type();
    if (wninit()) {		// open database 
	    cerr <<"wn: Fatal error - cannot open WordNet database" << endl;
	    exit (-1);
    }
    string str1, str2;
    string temp1, temp2;
    string temp;

    while (getline(in, temp))
    {
        str1 = temp.substr(0, temp.find('\t'));
        temp1 = temp.substr(0, temp.find('\t'));
        str2 = temp.substr(temp.find('\t') + 1);
        temp2 = temp.substr(temp.find('\t') + 1);
        str1 = do_is_defined(const_cast<char*>(str1.c_str()));
        str2 = do_is_defined(const_cast<char*>(str2.c_str()));
        if (str1 == "" && str2 != "")
        {
            //out << "Can't find " << temp1 << endl;
            out << temp1 << "\t" << temp2 << "\t0\t0\t1" << endl;
            continue;
        }
        else if (str2 == "" && str1 != "")
        {
            //out << "Can't find " << temp2 << endl;
            out << temp1 << "\t" << temp2 << "\t0\t1\t0" << endl;
            continue;
        }
        else if (str1 == "" && str2 == "")
        {
            out << temp1 << "\t" << temp2 << "\t0\t0\t0" << endl;
            continue;
        }
        memset(Color, 0, sizeof(Color));
        while (!SynQueue.empty())
        {
            SynQueue.pop();
        }
        out << temp1 << "\t" << temp2 << "\t" << 4.0 / (calPath(const_cast<char*>(str1.c_str()), const_cast<char*>(str2.c_str())) + 1) << "\t1\t1" << endl;
    }
    return 0;
}

static int calPath(char *str1, char *str2)
{
    int pos;
    int whichsense = ALLSENSES;
    /* Replace spaces with underscores before looking in database */

    strtolower(strsubst(str1, ' ', '_'));
    strtolower(strsubst(str2, ' ', '_'));
    if (!strcmp(str1, str2))
    {
        return 0;
    }
    for (pos = 1; pos <= NUMPARTS; ++pos)
    {
        do_search(str1, pos, OVERVIEW, ALLSENSES, SOURCE);
    }
    for (pos = 1; pos <= NUMPARTS; ++pos)
    {
        if (do_search(str2, pos, OVERVIEW, ALLSENSES, DESTINATION))
        {
            return 1;
        }
    }
    return BFS(str1);
}

static int do_search(char *searchword, int pos, int search, int whichsense, int sourceORdestination)
{
    SynsetPtr synsetPtr;
    long prefix = pos * 100000000;

    SynsetPtr freePtr = findtheinfo_ds(searchword, pos, search, whichsense);
    synsetPtr = freePtr;
    while(synsetPtr)
    {
        long synsetIndex = prefix + synsetPtr->hereiam;
        if (Color[synsetIndex])
        {
            return 1;
        }
        Color[synsetIndex] = sourceORdestination;
        synsetPtr = synsetPtr->nextss;
    }
    free_syns(freePtr);
    return 0;
}

static int BFS(char *searchword)
{
    SynsetPtr synsetPtr, freePtr;
    long prefix;
    long synsetIndex;
    for (int i = 0; optlist[i].option; ++i)
    {
        freePtr = findtheinfo_ds(searchword, optlist[i].pos, optlist[i].search, ALLSENSES);
        synsetPtr = freePtr;
        while (synsetPtr)
        {
            for (int i = 0; i < synsetPtr->ptrcount; ++i)
            {
                if (RelationType[synsetPtr->ptrtyp[i]])
                {
                    QUEUENODE node;
                    node.pos = synsetPtr->ppos[i];
                    node.offset = synsetPtr->ptroff[i];
                    prefix = node.pos * 100000000;
                    synsetIndex = prefix + node.offset;
                    if (Color[synsetIndex])
                    {
                        if (Color[synsetIndex] == -1)
                        {
                            return 2;
                        }
                        continue;
                    }
                    Color[synsetIndex] = 2;
                    SynQueue.push(node);
                }
            }
            synsetPtr = synsetPtr->nextss;
        }
        free_syns(freePtr);
    }
    while (!SynQueue.empty())
    {
        QUEUENODE node = SynQueue.front();
        long nodeIndex = node.pos * 100000000 + node.offset;
        SynQueue.pop();
        synsetPtr = read_synset(node.pos, node.offset, "");
        for (int i = 0; i < synsetPtr->ptrcount; ++i)
        {
            if (RelationType[synsetPtr->ptrtyp[i]])
            {
                QUEUENODE temp;
                temp.pos = synsetPtr->ppos[i];
                temp.offset = synsetPtr->ptroff[i];
                prefix = temp.pos * 100000000;
                synsetIndex = prefix + temp.offset;
                if (Color[synsetIndex])
                {
                    if (Color[synsetIndex] == -1)
                    {
                        return Color[nodeIndex] + 1;
                    }
                    continue;
                }
                Color[synsetIndex] = Color[nodeIndex] + 1;
                if (Color[synsetIndex] == 100)
                {
                    return -2;
                }
                SynQueue.push(temp);
            }
        }
        free_syns(synsetPtr);
    }
    return -3;
}
static void Init_type()
{
    memset(RelationType, 0, sizeof(RelationType));
    RelationType[1] = true;
    RelationType[2] = true;
    RelationType[38] = true;
    RelationType[3] = true;
    RelationType[39] = true;
    RelationType[6] = true;
    RelationType[7] = true;
    RelationType[8] = true;
    RelationType[9] = true;
    RelationType[10] = true;
    RelationType[11] = true;
    RelationType[18] = true;
    RelationType[20] = true;
    RelationType[4] = true;
    RelationType[14] = true;
    RelationType[16] = true;
    RelationType[5] = true;
    RelationType[17] = true;
    RelationType[12] = true;
    RelationType[13] = true;
    RelationType[15] = true;
}
static string do_is_defined(char *searchword)
{
    int i, found = 0;
    unsigned int search;
    char *morphword;

    /* Print all valid searches for word in all parts of speech */

    strtolower(strsubst(searchword, ' ', '_'));
	    
    for (i = 1; i <= NUMPARTS; i++) 
    {
    	if ((search = is_defined(searchword, i)) != 0) 
        {
            return searchword;
    	} 
        else
        {
    	    if ((morphword = morphstr(searchword, i)) != NULL)
            {
        	    do 
                {
        		    if ((search = is_defined(morphword, i)) != 0) 
                    {
                        return morphword;
        		    } 
        	    } while ((morphword = morphstr(NULL, i)) != NULL );
            }
        }
    }
    return "";
}
